#pragma once 
#include <any>
#include <typeinfo>
#include "EventLoop.hpp"
#include "Server.hpp"
#include "Buffer.hpp"
class Any
{
public:
    Any()
        :_content(nullptr)
    {}
    template <class T>//T是协议的类型
    Any(const T& val)//外部传入一个类型，根据这个类型进行构造
        :_content(new placeholder<T>(val))
    {}
    Any(const Any& other)
        :_content(other._content == nullptr ? nullptr : other._content->Clone())
    {}
    ~Any()//销毁_content
    {
        delete _content;
    }
    Any& Swap(Any& other)
    {
        std::swap(_content, other._content);//交换类的指针
        return *this;
    } 
    template <class T> 
    Any& operator=(const T& val)//通过数据类型进行赋值
    {
        Any(val).Swap(*this);//Any(val)表示生成的临时对象，和this交换内部_content指针后将会被销毁
        return *this;
    }
    Any& operator=(const Any& other)//通过其他的Any对象进行赋值
    {
        Any(other).Swap(*this);//原先this中保存的值也被释放了
        return *this;
    }
public:
    template <class T>
    T* Get()//返回子类对象保存的数据的指针
    {
        assert(typeid(T) == _content->Type());//获取的类型和保存的数据类型不一致
        return &((placeholder<T>*)_content)->_val;
    }
private:
    class holder//父类
    {
    public:
        virtual ~holder(){}
    public:
        virtual const std::type_info& Type() = 0;//纯虚函数，获取子类对象保存的类型
        virtual holder* Clone() = 0;//纯虚函数，通过一个子类对象克隆出一个新的子类对象
    };
    template<class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T& val)
            :_val(val)
        {}
    public:
        virtual const std::type_info& Type()//获取子类对象保存的类型
        {
            return typeid(T);
        }
        virtual holder* Clone()//针对当前自身的对象，克隆出一个新的子类对象
        {
            return new placeholder(_val);
        }
    public:
        T _val;//T类型的数据
    };
    holder* _content;//指向父类的指针 
};

typedef enum  
{
    DISCONNECTED,//连接关闭状态
    CONNECTING,//已连接但是各项回调还未被设置的中间状态
    CONNECTED,//已连接状态
    DISCONNECTING,//待关闭状态
}ConnState;
class Connection;//类的声明
using PtrConnection = std::shared_ptr<Connection>;
using ConnectedCallBack = std::function<void(const PtrConnection&)>;
using MessageCallBack = std::function<void(const PtrConnection&, Buffer*)>;
using ClosedCallBack = std::function<void(const PtrConnection&)>;//关闭阶段的处理回调
using AnyEventCallBack = std::function<void(const PtrConnection&)>;//任意事件触发的回调
//Connection模块是对Buffer模块，Socket模块，Channel模块的⼀个整体封装，
//实现了对⼀个通信套接字的管理，每⼀个进行数据通信的套接字（也就是accept获取到的新连接）都会使用Connection进行管理。
//Connection模块自己并不知道每个事件的该如何处理，所以需要外部使用者传入回调。
class Connection : public std::enable_shared_from_this<Connection>
{
public:
    Connection(EventLoop* loop, uint64_t connId, int sockfd)
        :_connId(connId)
        ,_sockfd(sockfd)
        ,_enableInactiveRelease(false)
        ,_loop(loop)
        ,_state(CONNECTING)
        ,_socket(_sockfd)
        ,_channel(loop, _sockfd)
    {
        _channel.SetCloseCallback(std::bind(&Connection::HandlerClose, this));
        _channel.SetEventCallback(std::bind(&Connection::HandlerEvent, this));
        _channel.SetReadCallback(std::bind(&Connection::HandlerRead, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandlerWrite, this));
        _channel.SetErrorCallback(std::bind(&Connection::HandlerError, this));
    }
    ~Connection() { DEBUG_LOG("RELEASE CONNECTION:%p", this); }  
public:
    //获取连接关联的文件描述符_sockfd
    int GetFd() { return _sockfd; }
    //获取_connId
    uint64_t GetConnId() { return _connId; } 
    //返回连接状态,判断一个连接是否是通信连接状态CONNECTED状态
    bool Connected() { return _state == CONNECTED; } 
    //设置上下文（连接建立完成时CONNECTING状态）
    void SetContext(const Any& context) { _context = context;}
    //获取上下文
    Any* GetContext() { return &_context; }
    //设置连接的回调函数
    void SetConnectedCallBack(const ConnectedCallBack& callback) { _connectedCallBack = callback; }
    //设置消息的回调函数
    void SetMessageCallBack(const MessageCallBack& callback) { _messageCallBack = callback; }
    //设置关闭的回调函数
    void SetClosedCallBack(const ClosedCallBack& callback) { _closeCallBack = callback; }
    //设置任意事件的回调函数
    void SetAnyEventCallBack(const AnyEventCallBack& callback) { _anyEventCallBack = callback; }
    //设置组件内的关闭连接的回调函数
    void SetServerClosedCallBack(const ClosedCallBack& callback) { _serverClosedCallBack = callback; }
    //连接获取之后CONNECTING状态下，要进行的各种设置（给channel设置事件回调，启动读监控，调用连接完成的回调：_connectedCallBack）
    void Established() { _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this)); }
    //发送数据，将数据放到发送缓冲区，启动写事件监控(外接传入的data，可能是临时变量，等到执行时已被释放，需要进行拷贝)
    void Send(const char* data, size_t len) 
    { 
        Buffer buffer;
        buffer.WriteAndPush(data, len);
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, buffer)); 
    }
    //提供给组件使用者的关闭接口,并不是立即关闭（先判断有没有数据待处理）
    void Shutdown() { _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this)); }
    //添加定时任务，启动非活跃的连接销毁,超过timeout即视为非活跃
    void EnableInactiveRelease(int timeout) { _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, timeout)); }
    //取消非活跃的连接的销毁
    void CancelInactiveRelease() { _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop, this)); }
    //协议切换(重置上下文以及阶段性的回调处理函数)-----该接口非线程安全,必须在EventLoop线程中立即被执行，防备新事件被触发，协议还未切换的情况
    void Upgrade(const Any& context, const ConnectedCallBack& conn, const MessageCallBack& msg, 
                                  const ClosedCallBack& closed, const AnyEventCallBack& event)
    {
        _loop->AssertInLoop();
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop, this, context, conn, msg, closed, event)); 
    }
private:  
    //五个channel的事件回调函数
    //描述符可读事件触发后调用的函数，接收socket数据放到接收缓冲区中，然后调用MessageCallBack
    void HandlerRead()
    {
        //1、接收socket数据放到缓冲区
        char buffer[65536];
        ssize_t ret = _socket.NonBlockRecv(buffer, 65535);//非阻塞接收数据
        if (ret < 0)//出错了,但是不能直接关闭连接，需要先处理完发动和接收缓冲区中的内容
        {
            return ShutdownInLoop();//提供给组件使用者的关闭接口,并不是实际关闭，需要判断有没有数据待发送（Shutdown的子函数）
        }
        else//大于表示接收到数据，等于表示没有读取到数据，处理方式都一样
        {
            _inBuffer.WriteAndPush(buffer, ret);//写入并移动void*类型数据
        }
        //2、调用messageCallBack进行业务处理(shared_from_this从当前对象自身获取自身的shared_ptr管理对象)（刷新活跃度）
        if (_inBuffer.ReadAbleSize() > 0) { _messageCallBack(shared_from_this(), &_inBuffer); }//如果输入缓冲区还有数据
    }
    //描述符可写事件触发后调用的函数，将发送缓冲区的数据进行发送
    void HandlerWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_outBuffer.ReadPosition(), _outBuffer.ReadAbleSize());//非阻塞发送数据
        if (ret < 0)//读取失败
        {
            if (_inBuffer.ReadAbleSize() > 0) 
            { 
                _messageCallBack(shared_from_this(), &_inBuffer); 
            }
            return ReleaseInLoop();//这个接口才是实际的关闭释放接口
        }
        _outBuffer.MoveReadOffset(ret);//将读偏移向后移动
        if (_outBuffer.ReadAbleSize() == 0)
        {
            _channel.DisableWrite();//关闭可写事件监控
            //如果当前是连接关闭状态，有数据则发送完数据释放连接，没有数据则直接释放
            if (_state == DISCONNECTING)
            {
                return ReleaseInLoop();
            }   
        }
    }
    //描述符挂断事件触发后调用的函数
    void HandlerClose()
    {
        if (_inBuffer.ReadAbleSize() > 0)//连接挂断，套接字什么都干不了，有数据待处理就处理一下，完毕关闭连接 
        { 
            _messageCallBack(shared_from_this(), &_inBuffer); 
        }
        return ReleaseInLoop();//这个接口才是实际的关闭释放接口
    }
    //描述符错误事件触发后调用的函数
    void HandlerError() { HandlerClose(); }
    //描述符任意事件触发后调用的函数,1、刷新连接的活跃度延迟定时销毁任务，调用组件使用者的任意事件回调
    void HandlerEvent()
    {
        if (_enableInactiveRelease == true) { _loop->TimerRefresh(_connId); }//如果开启了非活跃销毁刷新定时任务
        if (_anyEventCallBack) { _anyEventCallBack(shared_from_this()); }//调用组件使用者的任意事件回调
    }
    //连接获取之后CONNECTING状态下，要进行的各种设置（启动读监控，调用连接完成的回调）（Established的子函数）
    void EstablishedInLoop()
    {
        //1、修改连接状态2、启动读事件监控3、调用回调函数
        assert(_state == CONNECTING);//当前的状态必须是半连接状态
        _state = CONNECTED;//当前函数执行完毕，则连接进入已完成连接状态
        //一旦启动读事件监控就可能立即触发读事件（如果启动了非活跃连接的销毁，也找不到刷新活度的函数HandlerEvent，逻辑将有问题）
        _channel.EnableRead();//启动读事件监控
        if (_connectedCallBack) { _connectedCallBack(shared_from_this()); }
    }
    //这个接口才是实际的释放接口
    void ReleaseInLoop()
    {
        //1、修改链接状态，将其置为DISCONNECTED
        _state = DISCONNECTED;
        //2、移除连接的事件监控
        _channel.Remove();
        //3、关闭描述符
        _socket.Close();
        //4、如果当前定时器队列中还有定时销毁任务，则取消任务
        if (_loop->HasTimer(_connId)) { CancelInactiveReleaseInLoop(); }
        //5、调用关闭回调函数，避免先移除服务器的管理的连接信息导致Connection被释放，再去处理会出错，因此先调用用户的回调函数再调用服务器内部管理的连接信息
        if (_closeCallBack) { _closeCallBack(shared_from_this()); }//用户管理的连接信息
        if (_serverClosedCallBack) { _serverClosedCallBack(shared_from_this()); }//移除服务器内部管理的连接信息
    }
    //并不是实际的发送接口，而是将数据放到发送缓冲区，启动写事件监控（Send的子函数）
    void SendInLoop(Buffer buffer)
    {
        if (_state == DISCONNECTED) { return; }
        _outBuffer.WriteBufferAndPush(buffer);//写入并移动buffer类型数据
        if (_channel.WriteAble() == false) { _channel.EnableWrite(); }//启动写事件监控
    }
    //提供给组件使用者的关闭接口,并不是实际关闭，需要判断发送缓冲区有没有数据待发送（Shutdown的子函数）
    void ShutdownInLoop()
    {
        _state = DISCONNECTING;//设置连接为半关闭状态 
        if (_inBuffer.ReadAbleSize() > 0)//如果输入缓冲区中还有数据
        {
            if (_messageCallBack) { _messageCallBack(shared_from_this(), &_inBuffer); }
        }
        //要么就是写入数据的时候出错关闭，要么就是没有待发送的数据，直接关闭
        if (_outBuffer.ReadAbleSize() > 0)//如果输出缓冲区中还有数据
        {
            if (_channel.WriteAble() == false)//判断当前是否监控了可写
            {
                _channel.EnableWrite();//未监控可写，则进行监控
            } 
        }
        if (_outBuffer.ReadAbleSize() == 0) { ReleaseInLoop(); }
    }
    //添加定时任务，启动非活跃的连接销毁,超过timeout即视为非活跃（EnableInactiveRelease的子函数）
    void EnableInactiveReleaseInLoop(int timeout)
    {
        //1、将判断标志_enableInactiveRelease置为true
        _enableInactiveRelease = true;
        //2、如果当前定时销毁任务已存在，就刷新一下延迟
        if (_loop->HasTimer(_connId)) { _loop->TimerRefresh(_connId); }
        //3、如果不存在定时销毁任务，则新增
        _loop->TimerAdd(_connId, timeout, std::bind(&Connection::ReleaseInLoop, this));
    }
    //取消非活跃的连接的销毁（CancelInactiveRelease的子函数）
    void CancelInactiveReleaseInLoop()
    {
        _enableInactiveRelease = false;
        if (_loop->HasTimer(_connId)) { _loop->TimerCancel(_connId); }
    }
    //协议切换(重置上下文以及阶段性处理函数)（Upgrade的子函数）
    void UpgradeInLoop(const Any& context, const ConnectedCallBack& conn, const MessageCallBack& msg, 
                                  const ClosedCallBack& closed, const AnyEventCallBack& event)
    {
        _context = context;
        _connectedCallBack = conn;
        _messageCallBack = msg;
        _closeCallBack = closed;
        _anyEventCallBack = event;
    }
private:
    uint64_t _connId;//connect连接的唯一id，便于连接的管理和查找
    //uint64_t timerId;//定时器id，必须唯一，为了简化操作，使用_connId作为定时器id
    int _sockfd;//连接关联的文件描述符
    bool _enableInactiveRelease;//连接是否开启非活跃销毁的判断标志，默认为false，不启动非活跃销毁
    EventLoop* _loop;//连接所关联的一个EventLoop。
    ConnState _state;//连接状态
    Socket _socket;//服务器客户端二合一的类,对套接字进行管理
    Channel _channel;//连接的事件管理
    Buffer _inBuffer;//输入缓冲区（存放从socket中读取到的数据）
    Buffer _outBuffer;//存放要发送给对端的数据（并不是socket直接发送，而是要等描述符可写）
    Any _context;//请求的接收处理上下文（any通用数据类型）
    
    //这四个回调函数，是让组件使用者通过服务器模块进行设置
    ConnectedCallBack _connectedCallBack;//
    MessageCallBack _messageCallBack;//
    ClosedCallBack _closeCallBack;//
    AnyEventCallBack _anyEventCallBack;//组件使用者的任意事件回调
    //组件内的关闭连接回调，在组件内设置，因为服务器组件内会把所有连接管理起来，一旦某个连接要关闭，就应该从管理的地方移除自己的信息
    ClosedCallBack _serverClosedCallBack;
};